{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to atomman: Atoms class\n",
    "\n",
    "__Lucas M. Hale__, [lucas.hale@nist.gov](mailto:lucas.hale@nist.gov?Subject=ipr-demo), _Materials Science and Engineering Division, NIST_.\n",
    "    \n",
    "[Disclaimers](http://www.nist.gov/public_affairs/disclaimer.cfm) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## 1. Introduction<a id='section1'></a>\n",
    "\n",
    "The Atoms class collects per-atom properties. The basic behaviors of the class are:\n",
    "\n",
    "- The number of atoms is immutable after initializing.\n",
    "\n",
    "- The only default per-atom properties are an integer atomic type 'atype' and 3D position vector 'pos'.\n",
    "\n",
    "- Any other per-atom property can be freely assigned of any shape or type.\n",
    "\n",
    "- When creating a new per-atom property, values must be given for all atoms, and the types must be consistent. \n",
    "\n",
    "**Note**: The underlying structure of Atoms changed with version 1.2 to be more memory efficient and easier to work with.  The methods and attributes were designed with the old versions in mind, but there is no guarantee of complete backwards compatibility."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Library Imports**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atomman version = 1.4.0\n",
      "Notebook executed on 2021-08-03\n"
     ]
    }
   ],
   "source": [
    "# Standard Python libraries\n",
    "import datetime\n",
    "\n",
    "# http://www.numpy.org/\n",
    "import numpy as np\n",
    "\n",
    "# https://github.com/usnistgov/atomman\n",
    "import atomman as am\n",
    "\n",
    "# Show atomman version\n",
    "print('atomman version =', am.__version__)\n",
    "\n",
    "# Show date of Notebook execution\n",
    "print('Notebook executed on', datetime.date.today())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Basics<a id='section2'></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1. Initialization\n",
    "\n",
    "Parameters\n",
    "\n",
    "- **natoms** (*int, optional*) The number of atoms to associate with the Atoms instance. This is constant once the Atoms object is initialized. If not given, will be inferred from the length of atype and/or pos.\n",
    "- **atype** (*int or list of ints, optional*) The per-atom integer atomic types. If not given, atype is set to 1 for all atoms.\n",
    "- **pos** (*numpy.ndarray, optional*) The per-atom 3D atomic position vector.  If not given, pos is set to [0,0,0] for all atoms.  \n",
    "- **prop** (*dict, optional*) Dictionary containing all per-atom properties to set, alternate to passing the per-atom properties in as function parameters.  Included for backwards compatibility.\n",
    "- **\\*\\*kwargs** (*any*) Other keyword parameters can be given for defining extra per-atom properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   1.010 |   1.119 |   3.554\n",
      "      1 |       1 |   0.850 |   0.672 |   0.349\n",
      "      2 |       1 |   3.197 |   2.323 |   2.250\n",
      "      3 |       1 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       1 |   3.937 |   3.377 |   1.084\n",
      "      6 |       1 |   2.010 |   3.565 |   2.835\n",
      "      7 |       1 |   0.198 |   2.653 |   0.467\n",
      "      8 |       1 |   3.588 |   1.307 |   1.997\n",
      "      9 |       1 |   2.029 |   2.630 |   1.395\n"
     ]
    }
   ],
   "source": [
    "# Define 10 atom system with random positions\n",
    "# Notes: natoms inferred from first dimension of pos. Same atype assigned to all atoms\n",
    "atoms = am.Atoms(atype = 1, pos = 4 * np.random.rand(10, 3))\n",
    "print(atoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2. Pre-defined attributes\n",
    "\n",
    "The class has a few pre-defined attributes:\n",
    "\n",
    "- **natoms** is the number of atoms. len(Atoms) returns the same thing. \n",
    "- **atypes** gives a list of all unique atype values.\n",
    "- **natypes** gives the number of unique atype values.\n",
    "\n",
    "*Update version 1.3.0:* The way atypes and natypes are handled has changed. Backwards compatibility will be affected if previous Atoms had atype values of 0 or non-sequential atype values. The new method restricts atype values to be &ge; 1 and atypes returns all sequential integers from 1 through natypes=max(atype)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms.natoms ->  10\n",
      "len(atoms) ->    10\n",
      "atoms.atypes ->  (1,)\n",
      "atoms.natypes -> 1\n"
     ]
    }
   ],
   "source": [
    "print('atoms.natoms -> ', atoms.natoms)\n",
    "print('len(atoms) ->   ', len(atoms))\n",
    "print('atoms.atypes -> ', atoms.atypes)\n",
    "print('atoms.natypes ->', atoms.natypes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Per-atom properties <a id='section3'></a>\n",
    "\n",
    "The per-atom properties of an Atoms instance can be interacted with in one of three ways:\n",
    "\n",
    "- as attributes of the Atoms instance, i.e. atoms.myprop.\n",
    "\n",
    "- as items in the Atoms.view dictionary.\n",
    "\n",
    "- by calling the Atoms.prop() ([Section 6](#section6)) or Atoms.prop_atype() ([Section 7](#section7)) methods."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1. List assigned per-atom properties\n",
    "\n",
    "A list of all assigned per-atom properties can be retrieved using either:\n",
    "\n",
    "- atoms.prop()\n",
    "\n",
    "- atoms.view.keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms.prop() ->      ['atype', 'pos']\n",
      "atoms.view.keys() -> odict_keys(['atype', 'pos'])\n"
     ]
    }
   ],
   "source": [
    "print('atoms.prop() ->     ', atoms.prop())\n",
    "print('atoms.view.keys() ->', atoms.view.keys())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2. Accessing per-atom properties"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms.atype ->             [1 1 1 1 1 1 1 1 1 1]\n",
      "atoms.view['atype'] ->     [1 1 1 1 1 1 1 1 1 1]\n"
     ]
    }
   ],
   "source": [
    "print('atoms.atype ->            ', atoms.atype)\n",
    "print(\"atoms.view['atype'] ->    \", atoms.view['atype'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.3. Setting values of existing per-atom properties\n",
    "\n",
    "The same three options can be used for setting values to existing per-atom properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "setting: atoms.atype[2] = 2\n",
      "setting: atoms.view['atype'][5] = 2\n",
      "\n",
      "atoms.atype -> [1 1 2 1 1 2 1 1 1 1]\n"
     ]
    }
   ],
   "source": [
    "print('setting: atoms.atype[2] = 2')\n",
    "atoms.atype[2] = 2 \n",
    "\n",
    "print(\"setting: atoms.view['atype'][5] = 2\")\n",
    "atoms.view['atype'][5] = 2\n",
    "\n",
    "print()\n",
    "print('atoms.atype ->', atoms.atype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.4. Assigning new per-atom properties\n",
    "\n",
    "New per-atom properties can be assigned almost as easily as setting values of exising properties. The only limitations are that values must be given for all atoms and the data types and shapes must be consistent for all atoms. \n",
    "\n",
    "Value setting rules:\n",
    "\n",
    "- Values being assigned must either have no length, a length of 1, or a length of natoms.\n",
    "\n",
    "- If the value has no length or a length of 1, the value will be assigned to all atoms.\n",
    "\n",
    "- If the value as a length of natoms, each item in value will be assigned to a different atom."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms.prop() -> ['atype', 'pos', 'stress']\n",
      "\n",
      "atoms.stress[0] ->\n",
      "[[0. 0. 0.]\n",
      " [0. 0. 0.]\n",
      " [0. 0. 0.]]\n"
     ]
    }
   ],
   "source": [
    "# Assign stress as attribute (same value for all atoms)\n",
    "# Note first dimension is 1!\n",
    "atoms.stress = np.zeros([1, 3, 3])\n",
    "\n",
    "print('atoms.prop() ->', atoms.prop())\n",
    "print()\n",
    "\n",
    "print('atoms.stress[0] ->')\n",
    "print(atoms.stress[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.5. Viewing per-atom properties\n",
    "\n",
    "*Updated version 1.2.7*\n",
    "\n",
    "The string representation of atoms lists all assigned per-atom properties and shows id, atype and pos values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   1.010 |   1.119 |   3.554\n",
      "      1 |       1 |   0.850 |   0.672 |   0.349\n",
      "      2 |       2 |   3.197 |   2.323 |   2.250\n",
      "      3 |       1 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       2 |   3.937 |   3.377 |   1.084\n",
      "      6 |       1 |   2.010 |   3.565 |   2.835\n",
      "      7 |       1 |   0.198 |   2.653 |   0.467\n",
      "      8 |       1 |   3.588 |   1.307 |   1.997\n",
      "      9 |       1 |   2.029 |   2.630 |   1.395\n"
     ]
    }
   ],
   "source": [
    "print(atoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Alternatively, the atoms object can be copied into a pandas.DataFrame with the Atoms.df() method. This is convenient for viewing and analyzing all per-atom property values at once. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>atype</th>\n",
       "      <th>pos[0]</th>\n",
       "      <th>pos[1]</th>\n",
       "      <th>pos[2]</th>\n",
       "      <th>stress[0][0]</th>\n",
       "      <th>stress[0][1]</th>\n",
       "      <th>stress[0][2]</th>\n",
       "      <th>stress[1][0]</th>\n",
       "      <th>stress[1][1]</th>\n",
       "      <th>stress[1][2]</th>\n",
       "      <th>stress[2][0]</th>\n",
       "      <th>stress[2][1]</th>\n",
       "      <th>stress[2][2]</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>1.009574</td>\n",
       "      <td>1.118980</td>\n",
       "      <td>3.554220</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.850193</td>\n",
       "      <td>0.672331</td>\n",
       "      <td>0.349284</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>2</td>\n",
       "      <td>3.197080</td>\n",
       "      <td>2.323269</td>\n",
       "      <td>2.250059</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>1</td>\n",
       "      <td>2.875604</td>\n",
       "      <td>3.861164</td>\n",
       "      <td>3.046810</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>1</td>\n",
       "      <td>0.937406</td>\n",
       "      <td>2.569794</td>\n",
       "      <td>3.986789</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>3.937418</td>\n",
       "      <td>3.376766</td>\n",
       "      <td>1.084392</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>2.009608</td>\n",
       "      <td>3.564657</td>\n",
       "      <td>2.834760</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>7</td>\n",
       "      <td>1</td>\n",
       "      <td>0.198067</td>\n",
       "      <td>2.653309</td>\n",
       "      <td>0.466867</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>8</td>\n",
       "      <td>1</td>\n",
       "      <td>3.587661</td>\n",
       "      <td>1.306515</td>\n",
       "      <td>1.996816</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>9</td>\n",
       "      <td>1</td>\n",
       "      <td>2.029141</td>\n",
       "      <td>2.630481</td>\n",
       "      <td>1.395071</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   atype    pos[0]    pos[1]    pos[2]  stress[0][0]  stress[0][1]  \\\n",
       "0      1  1.009574  1.118980  3.554220           0.0           0.0   \n",
       "1      1  0.850193  0.672331  0.349284           0.0           0.0   \n",
       "2      2  3.197080  2.323269  2.250059           0.0           0.0   \n",
       "3      1  2.875604  3.861164  3.046810           0.0           0.0   \n",
       "4      1  0.937406  2.569794  3.986789           0.0           0.0   \n",
       "5      2  3.937418  3.376766  1.084392           0.0           0.0   \n",
       "6      1  2.009608  3.564657  2.834760           0.0           0.0   \n",
       "7      1  0.198067  2.653309  0.466867           0.0           0.0   \n",
       "8      1  3.587661  1.306515  1.996816           0.0           0.0   \n",
       "9      1  2.029141  2.630481  1.395071           0.0           0.0   \n",
       "\n",
       "   stress[0][2]  stress[1][0]  stress[1][1]  stress[1][2]  stress[2][0]  \\\n",
       "0           0.0           0.0           0.0           0.0           0.0   \n",
       "1           0.0           0.0           0.0           0.0           0.0   \n",
       "2           0.0           0.0           0.0           0.0           0.0   \n",
       "3           0.0           0.0           0.0           0.0           0.0   \n",
       "4           0.0           0.0           0.0           0.0           0.0   \n",
       "5           0.0           0.0           0.0           0.0           0.0   \n",
       "6           0.0           0.0           0.0           0.0           0.0   \n",
       "7           0.0           0.0           0.0           0.0           0.0   \n",
       "8           0.0           0.0           0.0           0.0           0.0   \n",
       "9           0.0           0.0           0.0           0.0           0.0   \n",
       "\n",
       "   stress[2][1]  stress[2][2]  \n",
       "0           0.0           0.0  \n",
       "1           0.0           0.0  \n",
       "2           0.0           0.0  \n",
       "3           0.0           0.0  \n",
       "4           0.0           0.0  \n",
       "5           0.0           0.0  \n",
       "6           0.0           0.0  \n",
       "7           0.0           0.0  \n",
       "8           0.0           0.0  \n",
       "9           0.0           0.0  "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df = atoms.df()\n",
    "df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note** that the values in the DataFrame are copies: calling Atoms.df() doubles the memory usage and changed values are not retained. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[3 1 2 1 1 2 1 1 1 1]\n",
      "[1 1 2 1 1 2 1 1 1 1]\n"
     ]
    }
   ],
   "source": [
    "df.loc[0, 'atype'] = 3\n",
    "print(df.atype.values)\n",
    "print(atoms.atype)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. Atoms by index<a id='section4'></a>\n",
    "\n",
    "The Atoms class also allows for the atoms to be get/set using numpy indexing.  This is useful for manipulations in how the atoms are listed and all per-atom properties for a given atom are to be retained.\n",
    "\n",
    "**Note:** If you want to access/manipulate per-atom properties of certain atoms, it is more efficient to access the properties first (as in [Section 3](#section3)) then apply the slice."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1. Getting by index\n",
    "\n",
    "An atoms object can be sliced using numpy indexing. This returns a new Atoms instance containing only the selected atom(s). Useful for generating subsets."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       2 |   3.197 |   2.323 |   2.250\n",
      "      1 |       2 |   3.937 |   3.377 |   1.084\n",
      "      2 |       1 |   3.588 |   1.307 |   1.997\n"
     ]
    }
   ],
   "source": [
    "# Get only the atoms with x position greater than 3\n",
    "upperatoms = atoms[atoms.pos[:, 0] > 3]\n",
    "print(upperatoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2. Setting by index\n",
    "\n",
    "All per-atom values of a subset of Atoms can be set at once using indexing. The value being assigned must be an Atoms instance of compatible size and same per-atom properties as the Atoms instance it is being assigned to."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       2 |   3.197 |   2.323 |   2.250\n",
      "      1 |       2 |   3.937 |   3.377 |   1.084\n",
      "      2 |       1 |   1.010 |   1.119 |   3.554\n"
     ]
    }
   ],
   "source": [
    "# Copy first atom in atoms to last atom in upperatoms\n",
    "upperatoms[-1] = atoms[0]\n",
    "print(upperatoms)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   1.010 |   1.119 |   3.554\n",
      "      1 |       1 |   0.850 |   0.672 |   0.349\n",
      "      2 |       2 |   3.197 |   2.323 |   2.250\n",
      "      3 |       1 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       2 |   3.937 |   3.377 |   1.084\n",
      "      6 |       1 |   2.010 |   3.565 |   2.835\n",
      "      7 |       1 |   0.198 |   2.653 |   0.467\n",
      "      8 |       1 |   3.588 |   1.307 |   1.997\n",
      "      9 |       1 |   2.029 |   2.630 |   1.395\n",
      "\n",
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.850 |   0.672 |   0.349\n",
      "      1 |       1 |   1.010 |   1.119 |   3.554\n",
      "      2 |       2 |   3.197 |   2.323 |   2.250\n",
      "      3 |       1 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       2 |   3.937 |   3.377 |   1.084\n",
      "      6 |       1 |   2.010 |   3.565 |   2.835\n",
      "      7 |       1 |   0.198 |   2.653 |   0.467\n",
      "      8 |       1 |   3.588 |   1.307 |   1.997\n",
      "      9 |       1 |   2.029 |   2.630 |   1.395\n"
     ]
    }
   ],
   "source": [
    "# Swap atoms 0 and 1 in atoms.\n",
    "print(atoms)\n",
    "print()\n",
    "\n",
    "atoms[[0, 1]] = atoms[[1, 0]]\n",
    "\n",
    "print(atoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. Atoms.extend() <a id='section5'></a>\n",
    "\n",
    "*Added version 1.2.8*\n",
    "\n",
    "The Atoms.extend method creates a new Atoms object by copying the current Atoms object and adding new atoms to it.  The new atoms can either be copied from another existing Atoms object, or a specified number of 'empty' atoms can be added.\n",
    "        \n",
    "Parameters\n",
    "- __value__ (*atomman.Atoms or int*) An int value will result in the atoms object being extended by that number of atoms, with all per-atom properties having default values (atype = 1, everything else = 0).  For an Atoms value, the current atoms list will be extended by the correct number of atoms and all per-atom properties in value will be copied over.  Any properties defined in one Atoms object and not the other will be set to default values.\n",
    "\n",
    "Returns\n",
    "- (*atomman.Atoms*) A new Atoms object containing all atoms and properties of the current object plus the additional atoms."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Passing Atoms.extend() an integer will add that many empty atoms to the end of the Atoms list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.850 |   0.672 |   0.349\n",
      "      1 |       1 |   1.010 |   1.119 |   3.554\n",
      "      2 |       2 |   3.197 |   2.323 |   2.250\n",
      "      3 |       1 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       2 |   3.937 |   3.377 |   1.084\n",
      "      6 |       1 |   2.010 |   3.565 |   2.835\n",
      "      7 |       1 |   0.198 |   2.653 |   0.467\n",
      "      8 |       1 |   3.588 |   1.307 |   1.997\n",
      "      9 |       1 |   2.029 |   2.630 |   1.395\n",
      "     10 |       1 |   0.000 |   0.000 |   0.000\n",
      "     11 |       1 |   0.000 |   0.000 |   0.000\n"
     ]
    }
   ],
   "source": [
    "print(atoms.extend(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Passing Atoms.extend() an Atoms object will combine the two Atoms lists."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.850 |   0.672 |   0.349\n",
      "      1 |       1 |   1.010 |   1.119 |   3.554\n",
      "      2 |       2 |   3.197 |   2.323 |   2.250\n",
      "      3 |       1 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       2 |   3.937 |   3.377 |   1.084\n",
      "      6 |       1 |   2.010 |   3.565 |   2.835\n",
      "      7 |       1 |   0.198 |   2.653 |   0.467\n",
      "      8 |       1 |   3.588 |   1.307 |   1.997\n",
      "      9 |       1 |   2.029 |   2.630 |   1.395\n",
      "     10 |       1 |   0.850 |   0.672 |   0.349\n",
      "     11 |       1 |   1.010 |   1.119 |   3.554\n",
      "     12 |       2 |   3.197 |   2.323 |   2.250\n",
      "     13 |       1 |   2.876 |   3.861 |   3.047\n"
     ]
    }
   ],
   "source": [
    "# Add copies of atoms 0,1,2,3 to the end\n",
    "print(atoms.extend(atoms[:4]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. Atoms.prop() <a id='section6'></a>\n",
    "\n",
    "The Atoms.prop() method offers a \"safe\" means of getting and setting values. It is designed with three things in mind:\n",
    "\n",
    "1. All get/set actions copy values instead of references.\n",
    "\n",
    "2. For consistency with the System.atoms_prop() method.\n",
    "\n",
    "3. For backwards compatibility with older atomman versions.\n",
    "\n",
    "Parameters:\n",
    "\n",
    "- **key** (*str, optional*) Per-atom property name.\n",
    "- **index** (*int, list, slice, optional*) Index of atoms.\n",
    "- **value** (*any, optional*) Property values to assign.\n",
    "- **a_id** (*int, optional*) Alternate name for index. Left in for backwards compatibility."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With no arguments, prop() returns the list of assigned per-atom properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['atype', 'pos', 'stress']\n"
     ]
    }
   ],
   "source": [
    "print(atoms.prop())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If the value parameter is not given, prop() will return a copy of the value associated with the key, index combination."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms.prop('atype') -> [1 1 2 1 1 2 1 1 1 1]\n",
      "\n",
      "atoms.prop(index=slice(1,5)) ->\n",
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   1.010 |   1.119 |   3.554\n",
      "      1 |       2 |   3.197 |   2.323 |   2.250\n",
      "      2 |       1 |   2.876 |   3.861 |   3.047\n",
      "      3 |       1 |   0.937 |   2.570 |   3.987\n",
      "\n",
      "atoms.prop(key='pos', index=0) ->\n",
      "[0.85019265 0.67233107 0.34928439]\n"
     ]
    }
   ],
   "source": [
    "# key by itself returns the property value\n",
    "print(\"atoms.prop('atype') ->\", atoms.prop('atype'))\n",
    "print()\n",
    "\n",
    "# index by itself returns an Atoms slice\n",
    "print('atoms.prop(index=slice(1,5)) ->')\n",
    "print(atoms.prop(index=slice(1,5)))\n",
    "print()\n",
    "\n",
    "# key and index returns property value(s) of specific atoms\n",
    "print(\"atoms.prop(key='pos', index=0) ->\")\n",
    "print(atoms.prop(key='pos', index=0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Values can be set to Atoms using the value parameter. Any values set are copied to the Atoms instance as opposed to assigned by reference."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "calling: atoms.prop(key='atype', value=7)\n",
      "atoms.prop('atype') -> [7 7 7 7 7 7 7 7 7 7]\n",
      "\n",
      "calling: atoms.prop(key='atype', index=4, value=1)\n",
      "atoms.prop('atype') -> [7 7 7 7 1 7 7 7 7 7]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Set all values of a given property\n",
    "print(\"calling: atoms.prop(key='atype', value=7)\")\n",
    "atoms.prop(key='atype', value=[7])\n",
    "print(\"atoms.prop('atype') ->\", atoms.prop('atype'))\n",
    "print()\n",
    "\n",
    "# Set the value of a specific atom's property\n",
    "print(\"calling: atoms.prop(key='atype', index=4, value=1)\")\n",
    "atoms.prop(key='atype', index=4, value=1)\n",
    "print(\"atoms.prop('atype') ->\", atoms.prop('atype'))\n",
    "print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "calling: atoms.prop(index=9, value=atoms.prop(index=0))\n",
      "per-atom properties = ['atype', 'pos', 'stress']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       7 |   0.850 |   0.672 |   0.349\n",
      "      1 |       7 |   1.010 |   1.119 |   3.554\n",
      "      2 |       7 |   3.197 |   2.323 |   2.250\n",
      "      3 |       7 |   2.876 |   3.861 |   3.047\n",
      "      4 |       1 |   0.937 |   2.570 |   3.987\n",
      "      5 |       7 |   3.937 |   3.377 |   1.084\n",
      "      6 |       7 |   2.010 |   3.565 |   2.835\n",
      "      7 |       7 |   0.198 |   2.653 |   0.467\n",
      "      8 |       7 |   3.588 |   1.307 |   1.997\n",
      "      9 |       7 |   0.850 |   0.672 |   0.349\n"
     ]
    }
   ],
   "source": [
    "# Copy atom 0 to atom 9 \n",
    "print(\"calling: atoms.prop(index=9, value=atoms.prop(index=0))\")\n",
    "atoms.prop(index=9, value=atoms.prop(index=0))\n",
    "print(atoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Demonstrate safe copy of prop() using only value parameter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms1 ->\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   0.000 |   0.000 |   0.000\n",
      "      2 |       1 |   0.000 |   0.000 |   0.000\n"
     ]
    }
   ],
   "source": [
    "# Generate atoms1 with 3 atoms (all with atype=1, pos=[0,0,0])\n",
    "atoms1 = am.Atoms(natoms=3)\n",
    "print('atoms1 ->')\n",
    "print(atoms1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "setting atoms2 = atoms1\n",
      "setting: atoms2.atype = 2\n",
      "atoms1 ->\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       2 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   0.000 |   0.000 |   0.000\n",
      "      2 |       2 |   0.000 |   0.000 |   0.000\n"
     ]
    }
   ],
   "source": [
    "# Directly setting atoms2 = atoms1 makes them point to the same reference\n",
    "print('setting atoms2 = atoms1')\n",
    "atoms2 = atoms1\n",
    "\n",
    "# Changing atoms2 changes atoms1\n",
    "print('setting: atoms2.atype = 2')\n",
    "atoms2.atype = 2\n",
    "\n",
    "print('atoms1 ->')\n",
    "print(atoms1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "setting: atoms3 = am.Atoms(natoms=3)\n",
      "calling: atoms3.prop(value=atoms1)\n",
      "atoms3 ->\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       2 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   0.000 |   0.000 |   0.000\n",
      "      2 |       2 |   0.000 |   0.000 |   0.000\n",
      "setting: atoms3.atype = 3\n",
      "atoms1 ->\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       2 |   0.000 |   0.000 |   0.000\n",
      "      1 |       2 |   0.000 |   0.000 |   0.000\n",
      "      2 |       2 |   0.000 |   0.000 |   0.000\n",
      "atoms3 ->\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       3 |   0.000 |   0.000 |   0.000\n",
      "      1 |       3 |   0.000 |   0.000 |   0.000\n",
      "      2 |       3 |   0.000 |   0.000 |   0.000\n"
     ]
    }
   ],
   "source": [
    "# Seting atoms3 to atoms1 using prop() copies values *not* reference.\n",
    "print('setting: atoms3 = am.Atoms(natoms=3)')\n",
    "atoms3 = am.Atoms(natoms=3)\n",
    "print('calling: atoms3.prop(value=atoms1)')\n",
    "atoms3.prop(value=atoms1)\n",
    "print('atoms3 ->')\n",
    "print(atoms3)\n",
    "# Changing atoms3 does not change atoms1\n",
    "print('setting: atoms3.atype = 3')\n",
    "atoms3.atype = 3\n",
    "\n",
    "print('atoms1 ->')\n",
    "print(atoms1)\n",
    "print('atoms3 ->')\n",
    "print(atoms3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. Atoms.prop_atype() <a id='section7'></a>\n",
    "\n",
    "*Added version 1.3.0*\n",
    "\n",
    "prop_atype() is a convenience method allowing for property values to be assigned to the atoms based on the atom’s corresponding atype values.\n",
    "\n",
    "Parameters\n",
    "\n",
    "- __key__ (*str*) Per-atom property name.\n",
    "- __value__ (*list, any*) Property value(s) to assign.  If atype is not given, this should be an object of length Atoms.natypes. Otherwise, should be a single per-atom value.\n",
    "- __atype__ (*int, optional*) A specific atype to assign value to."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "atoms ->\n",
      "per-atom properties = ['atype', 'pos']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   0.000 |   0.000 |   0.000\n",
      "      2 |       1 |   0.000 |   0.000 |   0.000\n",
      "      3 |       2 |   0.000 |   0.000 |   0.000\n",
      "      4 |       2 |   0.000 |   0.000 |   0.000\n",
      "      5 |       2 |   0.000 |   0.000 |   0.000\n",
      "      6 |       1 |   0.000 |   0.000 |   0.000\n",
      "      7 |       1 |   0.000 |   0.000 |   0.000\n",
      "      8 |       1 |   0.000 |   0.000 |   0.000\n",
      "      9 |       2 |   0.000 |   0.000 |   0.000\n"
     ]
    }
   ],
   "source": [
    "# Generate atoms with 10 atoms and two atom types\n",
    "atoms = am.Atoms(atype=[1,1,1,2,2,2,1,1,1,2])\n",
    "print('atoms ->')\n",
    "print(atoms)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>atype</th>\n",
       "      <th>pos[0]</th>\n",
       "      <th>pos[1]</th>\n",
       "      <th>pos[2]</th>\n",
       "      <th>charge</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>7</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>8</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>9</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   atype  pos[0]  pos[1]  pos[2]  charge\n",
       "0      1     0.0     0.0     0.0      -1\n",
       "1      1     0.0     0.0     0.0      -1\n",
       "2      1     0.0     0.0     0.0      -1\n",
       "3      2     0.0     0.0     0.0       1\n",
       "4      2     0.0     0.0     0.0       1\n",
       "5      2     0.0     0.0     0.0       1\n",
       "6      1     0.0     0.0     0.0      -1\n",
       "7      1     0.0     0.0     0.0      -1\n",
       "8      1     0.0     0.0     0.0      -1\n",
       "9      2     0.0     0.0     0.0       1"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Assign charges to the atoms based on atom type\n",
    "atoms.prop_atype('charge', [-1, 1])\n",
    "atoms.df()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>atype</th>\n",
       "      <th>pos[0]</th>\n",
       "      <th>pos[1]</th>\n",
       "      <th>pos[2]</th>\n",
       "      <th>charge</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>3</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>5</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>6</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>7</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>8</td>\n",
       "      <td>1</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>-1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <td>9</td>\n",
       "      <td>2</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   atype  pos[0]  pos[1]  pos[2]  charge\n",
       "0      1     0.0     0.0     0.0      -1\n",
       "1      1     0.0     0.0     0.0      -1\n",
       "2      1     0.0     0.0     0.0      -1\n",
       "3      2     0.0     0.0     0.0       0\n",
       "4      2     0.0     0.0     0.0       0\n",
       "5      2     0.0     0.0     0.0       0\n",
       "6      1     0.0     0.0     0.0      -1\n",
       "7      1     0.0     0.0     0.0      -1\n",
       "8      1     0.0     0.0     0.0      -1\n",
       "9      2     0.0     0.0     0.0       0"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Change the charges for only atoms with atype of 2\n",
    "atoms.prop_atype('charge', 0, atype=2)\n",
    "atoms.df()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. Atoms.model() <a id='section8'></a>\n",
    "\n",
    "*Added version 1.2.7*\n",
    "\n",
    "A JSON/XML equivalent data model representation of the Atoms object can be generated using the model() method. \n",
    "\n",
    "Parameters\n",
    "\n",
    "- __prop_name__ (*list, optional*) The Atoms properties to include.  If neither prop_name nor prop_unit are given, all system properties will be included.\n",
    "\n",
    "- __unit__ (*list, optional*) Lists the units for each prop_name as stored in the table.  For a value of None, no conversion will be performed for that property.  If neither unit nor prop_units given, pos will be given in Angstroms and all other values will not be converted.\n",
    "\n",
    "- __prop_unit__ (*dict, optional*) Dictionary where the keys are the property keys to include, and the values are units to use. If neither unit nor prop_units given,  pos will be given in Angstroms and all other values will not be converted.\n",
    "\n",
    "Returns\n",
    "        \n",
    "- (*DataModelDict.DataModelDict*) A JSON/XML data model for the current Atoms object. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\"atoms\": {\"natoms\": 10, \"property\": [{\"name\": \"atype\", \"data\": {\"value\": [1, 1, 1, 2, 2, 2, 1, 1, 1, 2]}}, {\"name\": \"pos\", \"data\": {\"value\": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], \"shape\": [10, 3], \"unit\": \"angstrom\"}}, {\"name\": \"charge\", \"data\": {\"value\": [-1, -1, -1, 0, 0, 0, -1, -1, -1, 0]}}]}}\n",
      "\n",
      "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n",
      "<atoms><natoms>10</natoms><property><name>atype</name><data><value>1</value><value>1</value><value>1</value><value>2</value><value>2</value><value>2</value><value>1</value><value>1</value><value>1</value><value>2</value></data></property><property><name>pos</name><data><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><value>0.0</value><shape>10</shape><shape>3</shape><unit>angstrom</unit></data></property><property><name>charge</name><data><value>-1</value><value>-1</value><value>-1</value><value>0</value><value>0</value><value>0</value><value>-1</value><value>-1</value><value>-1</value><value>0</value></data></property></atoms>\n"
     ]
    }
   ],
   "source": [
    "model = atoms.model()\n",
    "print(model.json())\n",
    "print()\n",
    "print(model.xml())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any stored model information can then be reloaded in as a new Atoms object by passing the 'model' parameter to the class initializer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "per-atom properties = ['atype', 'pos', 'charge']\n",
      "     id |   atype |  pos[0] |  pos[1] |  pos[2]\n",
      "      0 |       1 |   0.000 |   0.000 |   0.000\n",
      "      1 |       1 |   0.000 |   0.000 |   0.000\n",
      "      2 |       1 |   0.000 |   0.000 |   0.000\n",
      "      3 |       2 |   0.000 |   0.000 |   0.000\n",
      "      4 |       2 |   0.000 |   0.000 |   0.000\n",
      "      5 |       2 |   0.000 |   0.000 |   0.000\n",
      "      6 |       1 |   0.000 |   0.000 |   0.000\n",
      "      7 |       1 |   0.000 |   0.000 |   0.000\n",
      "      8 |       1 |   0.000 |   0.000 |   0.000\n",
      "      9 |       2 |   0.000 |   0.000 |   0.000\n"
     ]
    }
   ],
   "source": [
    "print(am.Atoms(model=model))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
